<template>
  <el-upload
    class="upload-advanced"
    :file-list="fileList"
    :multiple="multiple"
    :limit="limit"
    :http-request="uploadRequest"
    :on-preview="handlePreview"
    :on-remove="handleRemove"
    :before-upload="beforeUpload"
    :on-success="uploadSuccess"
    :accept="computedAccept"
    :drag="drag"
    :list-type="listType"
    :show-file-list="showFileList"
    v-bind="$attrs"
    :disabled="disabled"
  >
    <!-- 自定义上传框 -->
    <slot name="trigger"></slot>
    <div v-if="!$slots.trigger" class="upload-container" :style="uploadStyle">
      <el-icon v-if="uploadType === 'image'"><Plus /></el-icon>
      <el-icon v-else><UploadFilled /></el-icon>
      <div class="el-upload__text">{{ drag ? "拖拽文件或点击上传" : uploadText }}</div>
    </div>
    <!-- 上传框下方的提示说明文字 -->
    <template v-if="tip" #tip>
      <div class="el-upload__tip">{{ tipText }}</div>
    </template>
  </el-upload>

  <!-- 文件预览对话框（图片） -->
  <el-dialog v-model="previewVisible" width="60%">
    <img v-if="previewIsImage" :src="previewUrl" style="width: 100%" />
    <span v-else>暂不支持预览该类型文件</span>
  </el-dialog>
</template>

<script setup lang="ts" name="SvgIcon">
import { ref, watch } from "vue";
import type { UploadFile } from "element-plus";
import { ElMessage } from "element-plus";
import * as Api from "@/api/modules/media";

interface UploadFileItem {
  id: number;
  name: string;
  url: string;
  type?: string;
  [key: string]: any;
}

interface UploadAdvancedProps {
  modelValue?: UploadFileItem[]; // 文件列表
  multiple?: boolean; // 是否支持多选文件
  limit?: number; // 最大上传数量
  fileSizeLimit?: number; // 文件大小限制，单位MB
  accept?: string; // 文件类型
  drag?: boolean; // 是否支持拖拽上传
  disabled?: boolean; // 是否禁用
  listType?: "text" | "picture" | "picture-card"; // 文件列表类型
  showFileList?: boolean; // 是否显示文件列表
  isPublic?: string; // 是否公开 0:私有 1:公开
  uploadType?: "image" | "file" | "all"; // 上传类型
  tip?: string; // 提示文字
  uploadText?: string; // 上传按钮文字
  width?: string; // 宽度
  height?: string; // 高度
}

import { getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance();

const props = withDefaults(defineProps<UploadAdvancedProps>(), {
  showFileList: true,
  isPublic: "1",
  fileSizeLimit: 2,
  uploadType: "all",
  listType: "text",
  width: "130px",
  height: "130px",
  uploadText: "点击上传文件"
});
const emit = defineEmits(["update:modelValue", "uploadSuccess"]);

const fileList = ref<any[]>([]);

watch(
  () => props.modelValue,
  val => {
    fileList.value = (val || []).map(item => ({
      ...item,
      name: item.name,
      url: item.url,
      type: item.type || guessMimeType(item.url),
      status: "success",
      response: { media: { id: item.id, fileUrl: item.url } }
    }));
  },
  { immediate: true }
);
// 根据url判断文件类型
const guessMimeType = (url: string) => {
  const ext = url.split(".").pop()?.toLowerCase();
  if (!ext) return "";
  if (["png", "jpg", "jpeg", "gif", "webp"].includes(ext)) return "image";
  return "file";
};

// 限制文件大小
const beforeUpload = (file: File) => {
  const limit = props.fileSizeLimit;
  if (file.size / 1024 / 1024 > limit) {
    ElMessage.error(proxy.$safeT("msg.fileSizeLimit") + limit + "MB");
    return false;
  }

  if (props.uploadType === "image" && !file.type.startsWith("image/")) {
    ElMessage.error(proxy.$safeT("msg.onlyImage"));
    return false;
  }
  if (props.uploadType === "file" && file.type.startsWith("image/")) {
    ElMessage.error(proxy.$safeT("msg.unOnlyImage"));
    return false;
  }
  return true;
};

// 自定义上传请求
const uploadRequest = async (options: any) => {
  const { file, onSuccess, onError, onProgress } = options;

  const formData = new FormData();
  formData.append("file", file);
  formData.append("isPublic", String(props.isPublic)); // 0:私有 1:公开

  try {
    const res = await Api.addMedia(formData, onProgress);
    const media = res.data.media;
    const data = {
      id: media.id,
      name: file.name,
      url: media.fileUrl,
      type: file.type.startsWith("image/") ? "image" : "file"
    };
    emit("update:modelValue", [...(props.modelValue || []), data]);
    onSuccess({ media });
  } catch (e) {
    ElMessage.error(proxy.$safeT("msg.uploadedError"));
    onError(e);
  }
};

// 上传成功
const uploadSuccess = (response: any, uploadFile: UploadFile) => {
  if (!response) return;
  uploadFile.url = response.media.fileUrl;
  emit("uploadSuccess", response);
  ElMessage.success(proxy.$safeT("msg.uploadedSuccessfully"));
};

// 预览
const previewVisible = ref(false);
const previewUrl = ref("");
const previewIsImage = ref(false);

const handlePreview = (file: any) => {
  previewUrl.value = file.url;
  previewIsImage.value = file.type?.startsWith("image");
  previewVisible.value = true;
};

// 移除文件
const handleRemove = async (file: any) => {
  const id = file.id || file.response?.media?.id;
  if (!id) return ElMessage.warning("未找到文件 ID");
  await Api.delMedia(id);
  const list = (props.modelValue || []).filter(f => f.url !== file.url);
  emit("update:modelValue", list);
  ElMessage.success(proxy.$safeT("msg.delSuccess"));
};

const computedAccept = computed(() => {
  if (props.accept) return props.accept;
  if (props.uploadType === "image") return "image/*";
  if (props.uploadType === "file") return ".pdf,.doc,.docx,.xls,.xlsx,.zip,.rar";
  return "";
});

const uploadStyle = computed(() => ({
  width: props.width,
  height: props.height,
  display: "flex",
  flexDirection: "column" as const,
  alignItems: "center" as const,
  justifyContent: "center" as const
}));
const tipText = computed(() => props.tip || `可上传图片、文档、压缩包等 ${props.fileSizeLimit}MB以内）`);
</script>

<style scoped lang="scss">
.upload-container {
  width: v-bind(width);
  height: v-bind(height);
  user-select: none;
  border: 1px dashed #dcdfe6;
  border-radius: 4px;
}
.el-upload__text {
  font-size: 12px;
}
.el-upload__tip {
  text-align: center;
}
:deep(.el-upload-dragger) {
  padding: 0;
  border: none;
}
:deep(.el-upload--picture-card) {
  width: v-bind(width);
  height: v-bind(height);
  border: 0;
}
:deep(.el-upload-list--picture-card > .el-upload-list__item) {
  width: v-bind(width);
  height: v-bind(height);
}
</style>
